#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "x11eventfilter.h"
#include "x11clenteventfilter.h"

#include <QDebug>
#include "commonfunc.h"



MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
  , m_windowSystem(KWindowSystem::self())
  , m_x11Event_Filter(new X11EventFilter(this))
  ,m_X11Client_Filter(new X11ClentEventFilter(this))
{
    ui->setupUi(this);

    QObject::connect(m_windowSystem, &KWindowSystem::activeWindowChanged, this, &MainWindow::onActiveWindowChanged);
    QObject::connect(m_windowSystem, &KWindowSystem::windowAdded, this, &MainWindow::onWindowAdded);
    QObject::connect(m_windowSystem, &KWindowSystem::windowRemoved, this, &MainWindow::onWindowRemoved);
    QObject::connect(m_windowSystem, SIGNAL(windowChanged(WId id, NET::Properties properties, NET::Properties2 properties2)),
            this, SLOT(onWindowChanged(WId id, NET::Properties properties, NET::Properties2 properties2)));

    QObject::connect(
        m_x11Event_Filter,
        &X11EventFilter::buttonPress,
        ui->m_EventEdit,
        [=] (unsigned long win, int x, int y) {
            ui->m_EventEdit->appendPlainText(QString("    事件名:ButtonPress  位置：%1, %2")
                                   .arg(x).arg(y));
        },
        Qt::QueuedConnection);

    QObject::connect(
        m_x11Event_Filter,
        &X11EventFilter::buttonDrag,
        ui->m_EventEdit,
        [=] (unsigned long win, int x, int y) {
            ui->m_EventEdit->appendPlainText(QString("    事件名:ButtonDrag 位置：%1, %2")
                                   .arg(x).arg(y));
        },
        Qt::QueuedConnection);

    QObject::connect(
        m_x11Event_Filter,
        &X11EventFilter::buttonRelease,
        ui->m_EventEdit,
        [=] (unsigned long win, int x, int y) {
             ui->m_EventEdit->appendPlainText(QString("    事件名:ButtonRelease 位置：%1, %2")
                                   .arg(x).arg(y));
        },
        Qt::QueuedConnection);

    QObject::connect(
        m_x11Event_Filter,
        &X11EventFilter::keyPress,
        ui->m_EventEdit,
        [=] (unsigned long win, int code) {
            ui->m_EventEdit->appendPlainText(QString("    事件名:KeyPress  代码：%1")
                                   .arg(code));
        },
        Qt::QueuedConnection);

    QObject::connect(
        m_x11Event_Filter,
        &X11EventFilter::keyRelease,
        ui->m_EventEdit,
        [=] (unsigned long win, int code) {
            ui->m_EventEdit->appendPlainText(QString("    事件名:KeyRelease  代码：%1")
                                   .arg(code));
        },
        Qt::QueuedConnection);

    QObject::connect(
        m_X11Client_Filter,
        &X11ClentEventFilter::clientResize,
        ui->m_EventEdit,
        [=] (unsigned long win, QRect rect) {
            ui->m_EventEdit->appendPlainText(QString("进程ID：%1   窗口ID：%2   事件名:ConfigureNotify  位置：%3:%4 大小:%5:%6")
                                   .arg(m_ActivePid).arg(win)
                                   .arg(rect.x()).arg(rect.y()).arg(rect.width()).arg(rect.height()));
        },
        Qt::QueuedConnection);

    if (!m_x11Event_Filter->isRunning())
        m_x11Event_Filter->start();
    if (!m_X11Client_Filter->isRunning())
        m_X11Client_Filter->start();
    showAllWindowInfo();
}

MainWindow::~MainWindow()
{
    delete ui;
    delete m_x11Event_Filter;
    delete m_X11Client_Filter;
}

//显示所有窗口信息
void MainWindow::showAllWindowInfo()
{
    ui->m_AllWindowEdit->clear();
    m_WId_List.clear();
    //桌面窗口方式
    /*
    getAllWindow(m_WId_List);
    foreach(WId wid, m_WId_List)
    {
        QString sTitle = get_window_name(wid);
        quint32 pid = get_window_Pid(wid);
        QRect rect = get_window_rect(wid);
        ui->m_AllWindowEdit->appendPlainText(QString(tr("Title:%1   PID:%2   WID:%3   Rect:%4:%5-%6:%7"))
                                             .arg(sTitle).arg(pid).arg(wid)
                                             .arg(rect.x()).arg(rect.y()).arg(rect.width()).arg(rect.height()));
    }
    */

    //所有窗口方式
    SWindowLevel WindowLevel;
    Display *disp = XOpenDisplay(nullptr);       //获取默认的display指针
    Window root_window = DefaultRootWindow(disp);
    WindowLevel.window = root_window;
    WindowLevel.iLevel = 0;
    getAllWindow(WindowLevel);
    XCloseDisplay(disp);

    getSWindowLevelInfo(WindowLevel);
}

//显示当前窗口信息
void MainWindow::showActiveWindowInfo(WId wid)
{
    ui->m_ActiveEdit->clear();

    QString sTitle = get_window_name(wid);
    quint32 pid = get_window_Pid(wid);
    QRect rect = get_window_rect(wid);

    m_ActivePid = pid;
    m_ActiveWindow = wid;
    ui->m_ActiveEdit->appendPlainText(QString(tr("主窗口：Title:%1   PID:%2   WID:%3   Rect:%4:%5-%6:%7"))
                                         .arg(sTitle).arg(pid).arg(wid)
                                         .arg(rect.x()).arg(rect.y()).arg(rect.width()).arg(rect.height()));
    QList<WId> arrChildren;
    get_window_Children(wid, arrChildren);
    foreach(WId child, arrChildren)
    {
        QString sTitle = get_window_name(child);
        quint32 pid = get_window_Pid(child);
        QRect rect = get_window_rect(child);
        ui->m_ActiveEdit->appendPlainText(QString(tr("子窗口：Title:%1   PID:%2   WID:%3   Rect:%4:%5-%6:%7"))
                                             .arg(sTitle).arg(pid).arg(child)
                                             .arg(rect.x()).arg(rect.y()).arg(rect.width()).arg(rect.height()));
    }
}

//获取SWindowLevel信息
void MainWindow::getSWindowLevelInfo(SWindowLevel windowlevel)
{
    QString sLevel;
    for(int i=0; i<windowlevel.iLevel; i++)
        sLevel += "        ";
    if(windowlevel.iLevel>0)
        sLevel += "└";

    QString strRect = QString("Rect:%1:%2-%3:%4")
            .arg(windowlevel.rect.x()).arg(windowlevel.rect.y()).arg(windowlevel.rect.width()).arg(windowlevel.rect.height());
    QString strInfo = QString("%1 Title:'%2'  PID:'%3'   WID:'%4'    Parent:'%5'   Rect:'%6'")
            .arg(sLevel).arg(windowlevel.sTitle).arg(windowlevel.PID).arg(windowlevel.window).arg(windowlevel.parent).arg(strRect);
    ui->m_AllWindowEdit->appendPlainText(strInfo);
    foreach(SWindowLevel child, windowlevel.children)
        getSWindowLevelInfo(child);
}

void MainWindow::onActiveWindowChanged(WId id)
{
    showActiveWindowInfo(id);
}

void MainWindow::onWindowAdded(WId id)
{
    showAllWindowInfo();
}

void MainWindow::onWindowRemoved(WId id)
{
    showAllWindowInfo();
}

/***************************************
* 获取所有桌面窗口WID
***************************************/
void MainWindow::getAllWindow(QList<WId>& arrWId)
{
    arrWId = m_windowSystem->stackingOrder();
}

/***************************************
* 获取所有窗口WID
* 需要给定一个初始的RootWindow
***************************************/
void MainWindow::getAllWindow(SWindowLevel &windowLevel)
{
    windowLevel.sTitle  = get_window_name(windowLevel.window);
    windowLevel.PID     = get_window_Pid(windowLevel.window);
    windowLevel.rect    = get_window_rect(windowLevel.window);
    int subLevel = windowLevel.iLevel +1;

    Display *disp = XOpenDisplay(nullptr);       //获取默认的display指针   //获取默认的display指针
    Window    wRoot;
    Window    wParent;
    Window   *wChild;
    unsigned  nChildren;
    if(0 != XQueryTree(disp, windowLevel.window, &wRoot, &wParent, &wChild, &nChildren))
    {
        windowLevel.parent = wParent;
        for(unsigned i = 0; i < nChildren; i++)
        {
            SWindowLevel subWindowLevel;
            subWindowLevel.window = wChild[i];
            subWindowLevel.iLevel = subLevel;
            getAllWindow(subWindowLevel);
            windowLevel.children.append(subWindowLevel);
        }
    }
    XCloseDisplay(disp);
}

quint32 MainWindow::get_window_Pid(unsigned long win)
{
    Display *disp = XOpenDisplay(nullptr);       //获取默认的display指针
    Atom xa_prop_name;
    Atom xa_ret_type;
    int ret_format;
    unsigned long ret_nitems;
    unsigned long ret_bytes_after;
    unsigned char *ret_prop;
    quint32 id = 0;

    xa_prop_name = XInternAtom(disp, "_NET_WM_PID", False);  // 取对应字串的AtomID

    if (XGetWindowProperty(disp, win, xa_prop_name, 0,           // 获取窗口属性
                                MAX_PROPERTY_VALUE_LEN / 4,
                                False, XA_CARDINAL, &xa_ret_type,         // XA_CARDINAL为数值类型
                                &ret_format, &ret_nitems, &ret_bytes_after,
                                &ret_prop) != Success)       // 后五个参数是返回值
    {
         return id;
    }
    else
    {
         memcpy(&id, ret_prop, ret_format);// 类型传换
     }

    XCloseDisplay(disp);
    return  id;
}

QString MainWindow::get_window_name(unsigned long win)
{
    QString sTitle;
    char* buf = new char[1024];
    Display *disp = XOpenDisplay(nullptr);       //获取默认的display指针
    //使用_NET_WM_NAME方式获取窗口的名称
    XTextProperty tp;
    XGetTextProperty(disp,win,&tp,XInternAtom(disp, "_NET_WM_NAME", False));
    if (tp.nitems > 0)
    {
        int count = 0, i, ret;
        char **list = nullptr;
        ret = XmbTextPropertyToTextList(disp, &tp, &list, &count);
        if((ret == Success || ret > 0) && list != nullptr){
            for(i=0; i<count; i++)
                sprintf(buf,"%s", list[i]);
            XFreeStringList(list);
        } else {
            sprintf(buf,"%s", tp.value);
        }
        sTitle = QString::fromStdString(buf);
    }

    XCloseDisplay(disp);
    return  sTitle;
}

//获取对屏幕的坐标
QRect MainWindow::get_window_rect(unsigned long win)
{
    Display *disp = XOpenDisplay(nullptr);       //获取默认的display指针
    Window root_window = DefaultRootWindow(disp);

    QRect rect;
    int x, y;
    Window child;
    XWindowAttributes xwa;
    XTranslateCoordinates( disp, win, root_window, 0, 0, &x, &y, &child );
    XGetWindowAttributes( disp, win, &xwa );
    rect.setX(x - xwa.x);
    rect.setY(y - xwa.y);
    rect.setWidth(xwa.width);
    rect.setHeight(xwa.height);

    XCloseDisplay(disp);
    return  rect;
}

//获取子窗口
void MainWindow::get_window_Children(unsigned long win, QList<WId> &arrWId)
{
    qDebug() << "getChildren: \n root: " << win;
    Display *disp = XOpenDisplay(nullptr);       //获取默认的display指针

    Window    wRoot;
    Window    wParent;
    Window   *wChild;
    unsigned  nChildren;
    if(0 != XQueryTree(disp, win, &wRoot, &wParent, &wChild, &nChildren))
    {
        for(unsigned i = 0; i < nChildren; i++)
        {
            arrWId.append(wChild[i]);
            get_window_Children(wChild[i], arrWId);
        }
    }
}


void MainWindow::on_m_ListenBtn_clicked()
{
    if (!m_x11Event_Filter->isRunning())
        m_x11Event_Filter->start();
    if (!m_X11Client_Filter->isRunning())
        m_X11Client_Filter->start();
}
